package com.agent.tools;

import com.agent.config.WeatherConfig;
import dev.langchain4j.agent.tool.P;
import dev.langchain4j.agent.tool.Tool;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

import java.time.Duration;

///**
// * 天气工具：优先通过和风天气（QWeather）查询实况天气。
// * 使用顺序：先用城市名称通过 Geo API 获取 locationId，再查询 now 接口。
// */
@Component("weatherTools")
public class WeatherTools {

    /*
    和风天气API：https://dev.qweather.com/docs/api/weather/weather-now/

     */
    @Autowired
    private WeatherConfig weatherConfig;


    // 网络编程工具类，发送请求（带默认 User-Agent）
    private final WebClient webClient = WebClient.builder()
            .defaultHeader("User-Agent", "PersionAgent/1.0 (+https://example.local)")
            .build();

    // 天气查询函数调用
    @Tool(  name = "weather_now",
            value = "查询某个城市当前的天气（实况）。参数：city，如 '上海' 或 'Beijing'。返回简洁中文描述。")
    public String weatherNow(@P("城市") String city) {
        // 获取密钥
        String heKey = weatherConfig.getKey();
        System.out.println("[HeWeather][Now] API Key: " + heKey);
        if (city == null || city.isBlank()) {
            return "请提供城市名称";
        }
        if (heKey == null || heKey.isBlank()) {
            return "未配置和风天气API Key（external.heweather.key）";
        }
        try {
            // 1) 取得 locationId
            String geoUrl = String.format("https://n25u9vfp5c.re.qweatherapi.com/geo/v2/city/lookup?location=%s&key=%s", city, heKey);
            System.out.println("[HeWeather][Geo] GET " + geoUrl);
            String locationId = webClient.get().uri(geoUrl)
                    .exchangeToMono(resp -> resp.bodyToMono(String.class)
                            .defaultIfEmpty("")
                            .flatMap(body -> {
                                System.out.println("[HeWeather][Geo] GET " + geoUrl);
                                System.out.println("[HeWeather][Geo] Status: " + resp.statusCode());
                                System.out.println("[HeWeather][Geo] Body  : " + body);
                                if (resp.statusCode().is2xxSuccessful()) {
                                    return Mono.justOrEmpty(JsonUtils.extractQWeatherLocationId(body));
                                }
                                System.out.println("[HeWeather][Geo] Non-2xx response, treat as failure");
                                return Mono.just("");
                            })
                    )
                    .timeout(Duration.ofSeconds(8))
                    .onErrorResume(e -> {
                        System.out.println("[HeWeather][Geo] Error: " + e.getMessage());
                        e.printStackTrace();
                        return Mono.just("");
                    })
                    .block();
            System.out.println("[HeWeather] locationId: " + locationId);
            boolean usedFallback = false;
            if (locationId == null || locationId.isBlank()) {
                System.out.println("[HeWeather] Geo 未获取到 locationId，尝试使用城市名直接调用 Now 接口作为兜底: " + city);
                usedFallback = true;
                locationId = encode(city);
            }
            // 2) 查询实时天气
            String nowUrl = String.format("https://n25u9vfp5c.re.qweatherapi.com/v7/weather/now?location=%s&key=%s", locationId, heKey);
            String nowJson = webClient.get().uri(nowUrl)
                    .exchangeToMono(resp -> resp.bodyToMono(String.class)
                            .defaultIfEmpty("")
                            .flatMap(body -> {
                                System.out.println("[HeWeather][Now] GET " + nowUrl);
                                System.out.println("[HeWeather][Now] Status: " + resp.statusCode());
                                System.out.println("[HeWeather][Now] Body  : " + body);
                                if (resp.statusCode().is2xxSuccessful()) {
                                    return Mono.just(body);
                                }
                                System.out.println("[HeWeather][Now] Non-2xx response, treat as failure");
                                return Mono.just("");
                            })
                    )
                    .timeout(Duration.ofSeconds(8))
                    .onErrorResume(e -> {
                        System.out.println("[HeWeather][Now] Error: " + e.getMessage());
                        e.printStackTrace();
                        return Mono.just("");
                    })
                    .block();
            if (nowJson == null || nowJson.isBlank()) {
                if (usedFallback) {
                    return "查询天气失败：城市 '" + city + "' 可能不被接口识别，或网络/权限受限（Geo 404 & Now 失败）";
                }
                return "查询天气失败（网络或API错误）";
            }
            return JsonUtils.formatQWeatherNow(nowJson, city);
        } catch (Exception e) {
            return "查询天气时发生异常：" + e.getMessage();
        }
    }

    // 天气预报查询
    @Tool(name = "weather_7d_forecast",
            value = "查询某个城市未来7天的天气预报。参数：city，如 '上海' 或 'Beijing'。返回简洁中文描述。")
    public String weather7dForecast(@P("城市") String city) {
        // 获取密钥
        String heKey = weatherConfig.getKey();
        System.out.println("[HeWeather][7D] API Key: " + heKey);
        if (city == null || city.isBlank()) {
            return "请提供城市名称";
        }
        if (heKey == null || heKey.isBlank()) {
            return "未配置和风天气API Key（external.heweather.key）";
        }
        try {
            // 1) 取得 locationId
            String geoUrl = String.format("https://n25u9vfp5c.re.qweatherapi.com/geo/v2/city/lookup?location=%s&key=%s", city, heKey);
            System.out.println("[HeWeather][Geo] GET " + geoUrl);
            String locationId = webClient.get().uri(geoUrl)
                    .exchangeToMono(resp -> resp.bodyToMono(String.class)
                            .defaultIfEmpty("")
                            .flatMap(body -> {
                                if (resp.statusCode().is2xxSuccessful()) {
                                    return Mono.justOrEmpty(JsonUtils.extractQWeatherLocationId(body));
                                }
                                return Mono.just("");
                            })
                    )
                    .timeout(Duration.ofSeconds(8))
                    .onErrorResume(e -> Mono.just(""))
                    .block();
            if (locationId == null || locationId.isBlank()) {
                locationId = encode(city);
            }
            System.out.println("[HeWeather] locationId: " + locationId);
            // 2) 查询7天天气预报
            String forecastUrl = String.format("https://n25u9vfp5c.re.qweatherapi.com/v7/weather/7d?location=%s&key=%s", locationId, heKey);
            String forecastJson = webClient.get().uri(forecastUrl)
                    .exchangeToMono(resp -> resp.bodyToMono(String.class)
                            .defaultIfEmpty("")
                            .flatMap(body -> {
                                if (resp.statusCode().is2xxSuccessful()) {
                                    return Mono.just(body);
                                }
                                return Mono.just("");
                            })
                    )
                    .timeout(Duration.ofSeconds(8))
                    .onErrorResume(e -> Mono.just(""))
                    .block();
                    
            if (forecastJson == null || forecastJson.isBlank()) {
                return "查询天气预报失败（网络或API错误）";
            }
            System.out.println("[HeWeather][7D] GET " + forecastJson);
            return JsonUtils.formatQWeather7dForecast(forecastJson, city);
        } catch (Exception e) {
            return "查询天气预报时发生异常：" + e.getMessage();
        }
    }

    public String encode(String s) {
        try {
            return java.net.URLEncoder.encode(s, java.nio.charset.StandardCharsets.UTF_8);
        } catch (Exception e) {
            return s;
        }
    }

    /**
     * 轻量JSON处理工具，避免引入额外依赖：通过简单查找提取字段。
     * 生产环境建议使用Jackson等库。
     */
    static class JsonUtils {
        static String extractQWeatherLocationId(String json) {
            // 期望形如：{"code":"200","location":[{"id":"101010100", ...}]}
            if (json == null) return null;
            int idxLoc = json.indexOf("\"location\"");
            if (idxLoc < 0) return null;
            int idxIdKey = json.indexOf("\"id\"", idxLoc);
            if (idxIdKey < 0) return null;
            int idxColon = json.indexOf(':', idxIdKey);
            int idxQuoteStart = json.indexOf('"', idxColon + 1);
            int idxQuoteEnd = json.indexOf('"', idxQuoteStart + 1);
            if (idxQuoteStart < 0 || idxQuoteEnd < 0) return null;
            return json.substring(idxQuoteStart + 1, idxQuoteEnd);
        }

        static String formatQWeatherNow(String nowJson, String city) {
            // 期望：{"code":"200","now":{"text":"多云","temp":"27","feelsLike":"29","windDir":"东北风","windScale":"3"}}
            String code = findString(nowJson, "code");
            if (!"200".equals(code)) return "天气API返回非200状态";
            String text = findString(nowJson, "text");
            String temp = findString(nowJson, "temp");
            String feels = findString(nowJson, "feelsLike");
            String windDir = findString(nowJson, "windDir");
            String windScale = findString(nowJson, "windScale");
            StringBuilder sb = new StringBuilder();
            sb.append("【").append(city).append("】当前天气：").append(text != null ? text : "-");
            if (temp != null) sb.append("，气温").append(temp).append("°C");
            if (feels != null) sb.append("，体感").append(feels).append("°C");
            if (windDir != null) sb.append("，").append(windDir);
            if (windScale != null) sb.append("，风力").append(windScale).append("级");
            return sb.toString();
        }

        static String formatQWeather7dForecast(String forecastJson, String city) {
            // 期望：{"code":"200","daily":[{"fxDate":"2023-08-28","tempMax":"30","tempMin":"22","textDay":"多云","textNight":"晴","windDirDay":"东北风","windScaleDay":"1-2"}...]}
            String code = findString(forecastJson, "code");
            if (!"200".equals(code)) return "天气API返回非200状态，code=" + code;
            
            StringBuilder sb = new StringBuilder();
            sb.append("【").append(city).append("】未来7天天气预报：\n");
            
            // 解析daily数组中的数据
            int dailyStart = forecastJson.indexOf("\"daily\"");
            if (dailyStart < 0) return "无法解析天气预报数据";
            
            int arrayStart = forecastJson.indexOf('[', dailyStart);
            int arrayEnd = forecastJson.indexOf(']', arrayStart);
            if (arrayStart < 0 || arrayEnd < 0) return "无法解析天气预报数据";
            
            String dailyArray = forecastJson.substring(arrayStart+1, arrayEnd);
            
            // 分割每天的数据
            String[] dailyItems = dailyArray.split("\\},\\{");
            for (int i = 0; i < dailyItems.length && i < 7; i++) {
                String item = dailyItems[i];
                if (i == 0 && dailyItems.length > 1) {
                    item = item + "}";
                } else if (i == dailyItems.length - 1) {
                    item = "{" + item;
                } else if (dailyItems.length > 1) {
                    item = "{" + item + "}";
                }
                
                String fxDate = findString(item, "fxDate");
                String tempMax = findString(item, "tempMax");
                String tempMin = findString(item, "tempMin");
                String textDay = findString(item, "textDay");
                String textNight = findString(item, "textNight");
                String windDirDay = findString(item, "windDirDay");
                String windScaleDay = findString(item, "windScaleDay");
                
                // 格式化日期，只显示月日
                if (fxDate != null && fxDate.length() >= 10) {
                    fxDate = fxDate.substring(5, 10); // 只取"MM-dd"部分
                }
                
                sb.append(fxDate != null ? fxDate : "--");
                sb.append(" ").append(textDay != null ? textDay : "未知");
                sb.append(" ").append(tempMin != null ? tempMin : "--");
                sb.append("~").append(tempMax != null ? tempMax : "--").append("°C");
                if (windDirDay != null) sb.append(" ").append(windDirDay);
                if (windScaleDay != null) sb.append(windScaleDay).append("级");
                sb.append("\n");
            }
            
            return sb.toString().trim();
        }

        static String findString(String json, String key) {
            if (json == null) return null;
            String k = "\"" + key + "\"";
            int idx = json.indexOf(k);
            if (idx < 0) return null;
            int idxColon = json.indexOf(':', idx);
            if (idxColon < 0) return null;
            int i = idxColon + 1;
            // 跳过空白与引号
            while (i < json.length() && (Character.isWhitespace(json.charAt(i)) || json.charAt(i) == '"')) i++;
            int j = i;
            while (j < json.length() && json.charAt(j) != '"' && json.charAt(j) != ',' && json.charAt(j) != '}' ) j++;
            String raw = json.substring(i, j);
            // 去除尾部引号
            if (raw.endsWith("\"")) raw = raw.substring(0, raw.length()-1);
            // 去除首尾引号
            if (raw.startsWith("\"") && raw.endsWith("\"")) raw = raw.substring(1, raw.length()-1);
            return raw.replace("\\\"", "\"");
        }
    }
}
